Skip to content

feat(config): add additionalProperties support to generated config models#5131

Merged
xrmx merged 11 commits intoopen-telemetry:mainfrom
MikeGoldsmith:mike/config-additional-properties-support
Apr 24, 2026
Merged

feat(config): add additionalProperties support to generated config models#5131
xrmx merged 11 commits intoopen-telemetry:mainfrom
MikeGoldsmith:mike/config-additional-properties-support

Conversation

@MikeGoldsmith
Copy link
Copy Markdown
Member

@MikeGoldsmith MikeGoldsmith commented Apr 20, 2026

Description

Adds support for JSON Schema additionalProperties to the generated config dataclasses. This is the foundation for plugin/custom component loading in declarative file configuration — unknown component names (e.g. my_custom_sampler, my_custom_exporter) can now flow through typed dataclasses without being silently dropped.

Problem

The OTel configuration JSON schema defines additionalProperties on 12 types (Sampler, SpanExporter, TextMapPropagator, ExperimentalResourceDetector, LogRecordExporter, PushMetricExporter, etc.) to allow plugin component names as keys. However, datamodel-codegen ignores additionalProperties when generating plain Python dataclasses — there's no stdlib mechanism for it. Unknown kwargs are rejected by the dataclass __init__.

Solution

A custom datamodel-codegen template (opentelemetry-sdk/codegen/dataclass.jinja2) conditionally adds two things to affected classes:

  1. @_additional_properties_support decorator — wraps the dataclass __init__ to route unknown kwargs into an additional_properties instance attribute instead of raising TypeError
  2. additional_properties: ClassVar[dict[str, Any]] annotation — satisfies type checkers without creating a dataclass field, so additional_properties doesn't appear in __init__ signature, dataclasses.fields(), asdict(), or repr()

The decorator preserves the original inspect.signature() (for IDE autocompletion) and appends **kwargs to signal extras are accepted.

How it works

The template checks additionalPropertiesType, a context variable that datamodel-codegen sets for schema types where additionalProperties is a type object (e.g. {"type": ["object", "null"]}). This is how the OTel schema defines it for plugin-capable types.

Usage

from opentelemetry.sdk._configuration.models import Sampler

# Known sampler — works as before
s = Sampler(always_on={})
assert s.always_on == {}
assert s.additional_properties == {}

# Plugin sampler — unknown name captured
s = Sampler(my_custom_sampler={"ratio": 0.5})
assert s.additional_properties == {"my_custom_sampler": {"ratio": 0.5}}

Codegen

No changes to the codegen workflow — tox -e generate-config-from-jsonschema picks up the custom template via the custom-template-dir config in pyproject.toml.

Tests

  • TestAdditionalPropertiesSupport — 5 unit tests for the decorator (known fields, unknown fields, mixed, empty, signature preservation)
  • TestGeneratedModelsHaveAdditionalProperties — 6 regression tests verifying the key generated models accept unknown kwargs (guards against datamodel-codegen changing how it passes the template variable)

Schema types with additionalProperties (Sampler, SpanExporter,
TextMapPropagator, ExperimentalResourceDetector, etc.) now capture
unknown keyword arguments in an additional_properties dict field.
This enables plugin/custom component names to flow through typed
dataclasses without modifying the codegen tool.

Implementation:
- _additional_properties_support decorator in _common.py wraps the
  dataclass __init__ to route unknown kwargs into additional_properties
- Custom dataclass.jinja2 template for datamodel-codegen conditionally
  applies the decorator and field when additionalPropertiesType is set
- pyproject.toml updated with custom-template-dir and additional-imports
- models.py regenerated via tox -e generate-config-from-jsonschema

Assisted-by: Claude Opus 4.6
@MikeGoldsmith MikeGoldsmith moved this to Ready for review in Python PR digest Apr 20, 2026
@MikeGoldsmith MikeGoldsmith added the config Issues and PRs related to implementing Declarative Config label Apr 20, 2026
…kwargs

- Replace object.__setattr__ with plain self.additional_properties = extra
  (no frozen dataclasses, simpler and more Pythonic)
- Add pylint disable=unexpected-keyword-arg on test lines that intentionally
  pass unknown kwargs to verify the decorator captures them
- Add comment explaining setattr usage for __signature__ (pyright workaround)

Assisted-by: Claude Opus 4.6
Comment thread opentelemetry-sdk/codegen/dataclass.jinja2 Outdated
Comment thread opentelemetry-sdk/src/opentelemetry/sdk/_configuration/README.md
…perties

ClassVar tells type checkers the attribute exists without creating a
dataclass field. This means additional_properties doesn't appear in
__init__ signature, dataclasses.fields(), asdict(), or repr() — only
schema-defined fields show up. The decorator sets it as a plain
instance attribute at runtime.

Assisted-by: Claude Opus 4.6
…s-support' into mike/config-additional-properties-support
Comment thread pyproject.toml Outdated
Shorter name, aligns with the attribute it creates.

Assisted-by: Claude Opus 4.6
…s-support' into mike/config-additional-properties-support
@MikeGoldsmith MikeGoldsmith moved this from Ready for review to Approved PRs in Python PR digest Apr 24, 2026
@xrmx xrmx enabled auto-merge (squash) April 24, 2026 14:07
@xrmx xrmx merged commit dc28b95 into open-telemetry:main Apr 24, 2026
466 checks passed
@github-project-automation github-project-automation Bot moved this from Approved PRs to Done in Python PR digest Apr 24, 2026
@MikeGoldsmith MikeGoldsmith deleted the mike/config-additional-properties-support branch April 24, 2026 14:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

config Issues and PRs related to implementing Declarative Config

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants